package com.demo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.demo.exception.BusinessException;
import com.demo.mapper.UserMapper;
import com.demo.pojo.LoginInfo;
import com.demo.pojo.ResultVO;
import com.demo.pojo.User;
import com.demo.pojo.UserDTO;
import com.demo.service.UserService;
import com.demo.utils.CodeUtils;
import com.demo.utils.CurrentHolder;
import com.demo.utils.EmailApi;
import com.demo.utils.JwtUtils;
import jakarta.mail.MessagingException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {
    //判断密码是否符合要求
    private static final String PWD_REGEX = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[!@#$%^&*()=_+;':,.?]).{8,}$";
    @Autowired
    private EmailApi emailApi;
    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 发送验证码
     * @param email 需要收到验证码的邮箱
     * @return
     */
    @Override
    public ResultVO getCode(String email) throws MessagingException {
        //检查邮箱是否符合的格式
        if (!email.matches("^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\\.[a-zA-Z0-9]{2,6}$")) {
            throw new BusinessException("邮箱格式不正确！");
        }
        //邮箱是否已经存在
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("email", email);
        User one = this.getOne(userQueryWrapper);
        if (one != null) {
            throw new BusinessException("邮箱已存在！");
        }
        //如果验证码还在有效期内，则返回验证码还在有效期内
        if (redisTemplate.hasKey(email)) {
            throw new BusinessException("验证码还在有效期内！");
        }
        //生成验证码
        String code = CodeUtils.generateCode(6);
        //保存验证码
        redisTemplate.opsForValue().setIfAbsent(email, code, 10, TimeUnit.MINUTES);
        log.info("发送的验证码:{}", code);

        emailApi.sendVerificationEmail(email, "验证码", code, "register");
        return ResultVO.success();
    }

    /**
     * 注册账号
     * @param userDTO
     * @return
     */
    @Override
    public ResultVO register(UserDTO userDTO) {
        if(userDTO.getEmail() == null|| userDTO.getEmail().isEmpty()){
            throw new BusinessException("邮箱不能为空！");
        }
        if(userDTO.getUsername()==null|| userDTO.getUsername().isEmpty()){
            throw new BusinessException("用户名不能为空！");
        }
        if(userDTO.getPassword()==null|| userDTO.getPassword().isEmpty()){
            throw new BusinessException("密码不能为空！");
        }
        if(userDTO.getCode()==null|| userDTO.getCode().isEmpty()){
            throw new BusinessException("验证码不能为空！");
        }
        //密码必须包含大写、小写、数字和特殊字符，且长度是8位以上
        if (!userDTO.getPassword().matches(PWD_REGEX)) {
            throw new BusinessException("密码不符合要求！");
        }
        if (!redisTemplate.hasKey(userDTO.getEmail())) {
            throw new BusinessException("验证码已过期！");
        }
        if (!redisTemplate.opsForValue().get(userDTO.getEmail()).equals(userDTO.getCode())) {
            throw new BusinessException("验证码错误！");
        }
        redisTemplate.delete(userDTO.getEmail());
        //判断用户名是否存在
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("username", userDTO.getUsername());
        User one = this.getOne(userQueryWrapper);
        if (one != null) {
            throw new BusinessException("用户名已存在！");
        }
        //加密
        String password = DigestUtils.md5DigestAsHex(userDTO.getPassword().getBytes());
        userDTO.setPassword(password);
        User user = new User();
        BeanUtils.copyProperties(userDTO, user);

        boolean save = this.save(user);
        if (!save) {
            throw new BusinessException("注册失败！");
        }
        return ResultVO.success();
    }

    /**
     * 登录
     * @param userDTO
     * @return
     */
    @Override
    public ResultVO login(UserDTO userDTO) {
        //用户名和密码登录
        if (userDTO.getUsername() != null && !userDTO.getUsername().isEmpty() && userDTO.getPassword() != null && !userDTO.getPassword().isEmpty()) {
            QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
            userQueryWrapper.eq("username", userDTO.getUsername());
            User one = this.getOne(userQueryWrapper);
            if(one == null){
                throw new BusinessException("用户名不存在！");
            }
            if(!one.getPassword().equals(DigestUtils.md5DigestAsHex(userDTO.getPassword().getBytes()))){
                throw new BusinessException("密码错误！");
            }

            //生成JWT令牌
            Map<String, Object> claims = new HashMap<>();
            claims.put("id", one.getId());
            claims.put("username", one.getUsername());
            String jwt = JwtUtils.generateToken(claims);
            log.info("用户登录成功:{}", one);
            return ResultVO.success(new LoginInfo(one.getId(), one.getUsername(), jwt));
        }
        //通过邮箱和验证码登录
        if (userDTO.getEmail() != null && !userDTO.getEmail().isEmpty() && userDTO.getCode() != null && !userDTO.getCode().isEmpty()) {
            QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
            userQueryWrapper.eq("email", userDTO.getEmail());
            User one = this.getOne(userQueryWrapper);
            if(one == null){
                throw new BusinessException("邮箱不存在,请先注册！");
            }
            if(!redisTemplate.hasKey(userDTO.getEmail())){
                throw new BusinessException("验证码已过期！");
            }
            if(!redisTemplate.opsForValue().get(userDTO.getEmail()).equals(userDTO.getCode())){
                throw new BusinessException("验证码错误！");
            }
            redisTemplate.delete(userDTO.getEmail());
            //生成JWT令牌
            Map<String, Object> claims = new HashMap<>();
            claims.put("id", one.getId());
            claims.put("username", one.getUsername());
            String jwt = JwtUtils.generateToken(claims);
            log.info("用户登录成功:{}", one);
            return ResultVO.success(new LoginInfo(one.getId(), one.getUsername(), jwt));
        }




        throw new BusinessException("登录失败");

    }

    /**
     * 登录验证码
     * @param email
     * @return
     */
    @Override
    public ResultVO getCodeLogin(String email) throws MessagingException {
        if(email == null|| email.isEmpty()){
            throw new BusinessException("邮箱不能为空！");
        }
        //检查邮箱是否符合的格式
        if (!email.matches("^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\\.[a-zA-Z0-9]{2,6}$")) {
            throw new BusinessException("邮箱格式不正确！");
        }
        if(redisTemplate.hasKey(email)){
            throw new BusinessException("验证码还在邮箱期！");
        }
        //生成验证码
        String code = CodeUtils.generateCode(6);
        //保存验证码
        redisTemplate.opsForValue().setIfAbsent(email, code, 10, TimeUnit.MINUTES);
        log.info("发送的登录验证码:{}", code);
        emailApi.sendVerificationEmail(email, "验证码", code, "login");
        return ResultVO.success();

    }

    /**
     * 修改密码
     * @param userDTO
     * @return
     */
    @Override
    public ResultVO updatePassword(UserDTO userDTO) {
        if(userDTO.getEmail()==null|| userDTO.getEmail().isEmpty()){
            throw new BusinessException("邮箱不能为空！");
        }
        //密码必须包含大写、小写、数字和特殊字符，且长度是8位以上
        if (!userDTO.getPassword().matches(PWD_REGEX)) {
            throw new BusinessException("密码不符合要求！密码必须包含大写、小写、数字和特殊字符，且长度是8位以上");
        }
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("email", userDTO.getEmail());
        User one = this.getOne(userQueryWrapper);
        if(one == null){
            throw new BusinessException("邮箱不存在！");
        }
        one.setPassword(DigestUtils.md5DigestAsHex(userDTO.getPassword().getBytes()));
        boolean update = this.updateById(one);
        if(!update){
            throw new BusinessException("修改密码失败！");
        }
        log.info("修改密码成功:{}", one);
        return ResultVO.success();
    }

    /**
     * 忘记密码发送验证码
     * @param email
     * @return
     */
    @Override
    public ResultVO getCodeForget(String email) throws MessagingException {
        if(email == null|| email.isEmpty()){
            throw new BusinessException("邮箱不能为空！");
        }
        //检查邮箱是否符合的格式
        if (!email.matches("^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\\.[a-zA-Z0-9]{2,6}$")) {
            throw new BusinessException("邮箱格式不正确！");
        }
        if(redisTemplate.hasKey(email)){
            throw new BusinessException("验证码还在邮箱期！");
        }
        //生成验证码
        String code = CodeUtils.generateCode(6);
        //保存验证码
        redisTemplate.opsForValue().setIfAbsent(email, code, 10, TimeUnit.MINUTES);
        log.info("发送的忘记密码的验证码:{}", code);
        emailApi.sendVerificationEmail(email, "验证码", code, "forget");
        return ResultVO.success();
    }

    @Override
    public ResultVO<User> getCurrentUser() {
        Long currentId = CurrentHolder.getCurrentId();
        User one = this.getOne(new QueryWrapper<User>().eq("id", currentId));
        if(one == null){
            throw new BusinessException("用户不存在！");
        }
        one.setPassword("****************");
        log.info("获取当前用户成功:{}", one);

        return ResultVO.success(one);
    }
}
